package api

import (
	"encoding/json"
	"epg/privilege"
	"epg/utils"
	"net/http"
	_ "net/http/pprof" //pprof
	"sync"
	"time"

	"github.com/zeast/logs"
	"sync/atomic"
	"epg/jmconf"
	"strconv"
)

//apiServer the api Server
type apiServer struct {
	sync.Mutex
	lastSyncTime time.Time
	syncStatus   uint8
}

var api *apiServer

func init() {
	api = &apiServer{syncStatus: SyncNone}
}

//StartService start the api Server
func StartService(addr string) {
	http.HandleFunc("/health", handleHealth)
	http.HandleFunc("/sync_priv", handleSyncPriv)
	http.HandleFunc("/change_log_level", handleChangeLogLevel)
	http.HandleFunc("/settings",Settings)
	go func() {
		defer utils.PrintPanicStack()
		logs.Info("API Service Running on :", addr)
		logs.Error(http.ListenAndServe(addr, nil))
	}()
}

//respJSON write the json data to the Writer.
func respJSON(w http.ResponseWriter, data interface{}) error {
	bytes, err := json.Marshal(data)
	if err != nil {
		logs.Error(err)
		return err
	}
	w.Header().Set("Content-Type", "application/json;charset=utf-8")
	_, err = w.Write(bytes)
	if err != nil {
		logs.Error(err)
	}
	return err
}

//handleHealth
func handleHealth(w http.ResponseWriter, req *http.Request) {
	respJSON(w, Reply{Status: StatusOK, Time: time.Now().Unix(), Msg: "NodeServicing"})
}

//handleSyncPriv
func handleSyncPriv(w http.ResponseWriter, req *http.Request) {
	logs.Info("api call reload privilege")
	if req.Method != "POST" {
		respJSON(w, Reply{Status: StatusErr, Time: api.lastSyncTime.Unix(), Msg: "非法请求"})
		logs.Error("非法的同步用户权限请求")
		return
	}

	if time.Now().Sub(api.lastSyncTime) < time.Minute {
		respJSON(w, Reply{Status: StatusErr, Time: api.lastSyncTime.Unix(), Msg: "两次权限同步需要间隔一分钟以上"})
		logs.Error("两次权限同步需要间隔一分钟以上")
		return
	}

	if api.syncStatus != SyncNone {
		respJSON(w, Reply{Status: StatusErr, Time: time.Now().Unix(), Msg: "节点状态异常，不能进行同步"})
		logs.Error("节点状态异常，不能进行同步")
		return
	}

	api.lastSyncTime = time.Now()
	api.syncStatus = SyncIng
	msg := "reload ok"
	err := privilege.AuthChecker.Reload()
	if err != nil {
		msg = err.Error()
		api.syncStatus = SyncErr
	} else {
		api.syncStatus = SyncFin
	}
	reply := &Reply{Status: StatusOK, Time: time.Now().Unix(), Msg: msg}
	api.syncStatus = SyncNone
	respJSON(w, reply)
}

func handleChangeLogLevel(w http.ResponseWriter, req *http.Request) {
	logs.Info("api call change log level")
	if req.Method != "POST" {
		respJSON(w, Reply{Status: StatusErr, Time: time.Now().Unix(), Msg: "非法请求"})
		logs.Error("非法的改变服务器日志等级")
		return
	}

	lv := req.PostFormValue("level")

	logs.SetLogLevelStr(lv)

	respJSON(w, Reply{Status: StatusOK, Time: time.Now().Unix(), Msg: "设置成功"})
	return
}

func Settings(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		setSettings (w, r)
	 }else {
		respJSON(w, Reply{Status: StatusErr, Time: time.Now().Unix(), Msg: "非法请求"})
	}


}

func setSettings(w http.ResponseWriter, r *http.Request){
	key := r.PostFormValue("key")
	value := r.PostFormValue("value")

	switch key {
	case "log_level":
		logs.SetLogLevelStr(value)

	case "get_mysql_conn_timeout":
		t , err := strconv.Atoi(value)
		if err != nil {
			logs.Error(err)
			respJSON(w, Reply{Status: StatusErr, Time: time.Now().Unix(), Msg: "非法请求"})
			return
		}

		atomic.StoreUint32(&jmconf.Cfg.GetMysqlConnTimeout,uint32(t))

	default:
		respJSON(w, Reply{Status: StatusErr, Time: time.Now().Unix(), Msg: "非法请求"})
	}

	respJSON(w, Reply{Status: StatusOK, Time: time.Now().Unix(), Msg: "设置成功"})
}
